package com.ptl.bp.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;

public class SensitiveDataSerializer extends StdSerializer<Object> implements ContextualSerializer {
    private final DataAccessEnum[] allowedRoles;
    private final Pattern maskPattern;
    private final String maskReplacement;
    private final Class<?> fieldType;

    public SensitiveDataSerializer() {
        super(Object.class);
        this.allowedRoles = new DataAccessEnum[0];
        this.maskPattern = Pattern.compile("");
        this.maskReplacement = "*";
        this.fieldType = Object.class;
    }

    public SensitiveDataSerializer(DataAccessEnum[] allowedRoles, String maskPattern,
                                   String maskReplacement, Class<?> fieldType) {
        super(Object.class);
        this.allowedRoles = allowedRoles;
        this.maskPattern = Pattern.compile(maskPattern);
        this.maskReplacement = maskReplacement;
        this.fieldType = fieldType;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }

        // 获取当前用户权限
        List<String> mockRoles = Optional.ofNullable(GlobalUserContext.getUser()).map(v-> Collections.singletonList(v.getRole().name())).orElse(new ArrayList<>());
        boolean shouldMask = Arrays.stream(allowedRoles)
                .noneMatch(role -> mockRoles.contains(role.name()));

        if (!shouldMask || true) {
            gen.writeObject(value);
            return;
        }

        // 根据字段类型进行脱敏
        Object maskedValue = maskValueByType(value);
        gen.writeObject(maskedValue);
    }

    private Object maskValueByType(Object value) {
        String valueStr = value.toString();

        // 优先使用自定义正则表达式
        if (!maskPattern.pattern().isEmpty()) {
            return maskPattern.matcher(valueStr).replaceAll(maskReplacement);
        }

        // 如果没有配置自定义正则，根据字段类型使用智能脱敏
        if (fieldType == String.class) {
            return maskString(valueStr);
        } else if (isNumberType(fieldType)) {
            return maskNumber(valueStr);
        } else if (fieldType == Boolean.class || fieldType == boolean.class) {
            return maskBoolean();
        } else {
            return maskObject(value);
        }
    }

    private boolean isNumberType(Class<?> type) {
        return Number.class.isAssignableFrom(type) ||
                type == int.class || type == long.class ||
                type == double.class || type == float.class ||
                type == byte.class || type == short.class;
    }

    private String maskNumber(String numberStr) {
        if (numberStr.length() <= 4) {
            return repeatString(maskReplacement, numberStr.length());
        } else {
            // 数字：保留前后各2位，中间用*替换
            int keepLength = Math.min(2, numberStr.length() / 4);
            return numberStr.substring(0, keepLength) +
                    repeatString(maskReplacement, numberStr.length() - keepLength * 2) +
                    numberStr.substring(numberStr.length() - keepLength);
        }
    }

    private String maskString(String text) {
        if (text == null || text.isEmpty()) return text;
        if (text.length() <= 2) {
            return repeatString(maskReplacement, text.length());
        } else if (text.length() <= 5) {
            // 短文本：保留第1个字符，后面用*替换
            return text.charAt(0) + repeatString(maskReplacement, text.length() - 1);
        } else {
            // 长文本：保留前后各2个字符，中间用*替换
            int keepLength = 2;
            return text.substring(0, keepLength) +
                    repeatString(maskReplacement, text.length() - keepLength * 2) +
                    text.substring(text.length() - keepLength);
        }
    }

    private Object maskBoolean() {
        return null;
    }

    private Object maskObject(Object obj) {
        return null;
    }

    private String repeatString(String str, int count) {
        if (count <= 0) return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append(str);
        }
        return sb.toString();
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        SensitiveData ann = property.getAnnotation(SensitiveData.class);
        if (ann == null) {
            // return prov.findValueSerializer(property.getType(), property);
            return this;
        }
        return new SensitiveDataSerializer(ann.hasAnyRole(), ann.maskPattern(),
                ann.maskReplacement(), property.getType().getRawClass());
    }
}